#!/usr/bin/env bash

# Copyright 2023 Flant JSC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

source /shell_lib.sh

function __config__(){
  cat <<EOF
configVersion: v1
kubernetes:
  - name: users
    apiVersion: deckhouse.io/v1
    kind: User
    queue: "users"
    group: main
    executeHookOnEvent: []
    executeHookOnSynchronization: false
    keepFullObjectsInMemory: false
    jqFilter: |
      {
        "name": .metadata.name,
        "userID": .spec.userID,
        "email": .spec.email,
        "groups": .spec.groups
      }
kubernetesValidating:
- name: users-unique.deckhouse.io
  group: main
  rules:
  - apiGroups:   ["deckhouse.io"]
    apiVersions: ["*"]
    operations:  ["CREATE", "UPDATE"]
    resources:   ["users"]
    scope:       "Cluster"
EOF
}

function __main__() {
  operation=$(context::jq -r '.review.request.operation')
  userName=$(context::jq -r '.review.request.object.metadata.name')
  userID=$(context::jq -r '.review.request.object.spec.userID')
  email=$(context::jq -r '.review.request.object.spec.email')
  groups=$(context::jq -r '.review.request.object.spec.groups // ""')

  if userWithTheSameEmail="$(context::jq -er --arg name "$userName" --arg email "$email" '.snapshots.users[].filterResult | select(.name != $name) | select(.email == $email) | .name' 2>&1)"; then
    cat <<EOF > "$VALIDATING_RESPONSE_PATH"
{"allowed":false, "message":"users.deckhouse.io \"$userName\", user \"$userWithTheSameEmail\" is already using email \"$email\"" }
EOF
    return 0
  fi

  if ([ "$operation" == "CREATE" ] || [ "$operation" == "UPDATE" ]) && [ "$userID" != "null" ]; then
    cat <<EOF > "$VALIDATING_RESPONSE_PATH"
{"allowed":true, "warnings":["\".spec.userID\" is deprecated and shouldn't be set manually (if set, its value is ignored)"]}
EOF
    return 0
  fi

  if [ "$operation" == "CREATE" ] && [ "$groups" != "" ]; then
    cat <<EOF > "$VALIDATING_RESPONSE_PATH"
{"allowed":false, "message":"\".spec.groups\" is deprecated, use the \"Group\" object." }
EOF
    return 0
  fi

  if context::jq -er --arg name "$userName" '
        .review as $review |
        if ($review.request.operation == "UPDATE") and ($review.request.object.spec.groups | length > 0)
        then
          .snapshots.users[].filterResult |
          select(.name == $name) |
          (($review.request.object.spec.groups | sort) - (.groups | sort)) |
          length > 0
        else
          false
        end
        ' >/dev/null 2>&1
  then
    cat <<EOF > "$VALIDATING_RESPONSE_PATH"
{"allowed":false, "message":"\".spec.groups\" is deprecated, modification is forbidden, only removal of all elements is allowed" }
EOF
    return 0
  fi

  if context::jq -er '.review.request.object.spec.email | startswith("system:")' >/dev/null 2>&1; then
    cat <<EOF > "$VALIDATING_RESPONSE_PATH"
{"allowed":false, "message":"users.deckhouse.io \"$userName\", \".spec.email\" must not start with the \"system:\" prefix" }
EOF
    return 0
  fi

  cat <<EOF > "$VALIDATING_RESPONSE_PATH"
{"allowed":true}
EOF

}

hook::run "$@"
